﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using Barbar.MapReport.Common;
using System.Collections.ObjectModel;
using System.IO;

namespace Barbar.MapReport.HtmlRender {
  internal class ReplacementTemplate {
    private SortedList<string, string> m_Messages = new SortedList<string, string>();
    private SortedList<string, bool> m_Conditions = new SortedList<string, bool>();

    private class ReplacementEntry {
      private int m_Start;
      private int m_End;
      private string m_Content;

      public ReplacementEntry(int start, int end, string content) {
        m_Start = start;
        m_End = end;
        m_Content = content;
      }

      public string Content {
        get { return m_Content; }
        set { m_Content = value; }
      }

      public int Start {
        get { return m_Start; }
        set { m_Start = value; }
      }

      public int End {
        get { return m_End; }
        set { m_End = value; }
      }
    }

    public void AddMessage(string key, string value) {
      m_Messages.Add(key, value);
    }

    public void AddCondition(string key, bool value) {
      m_Conditions.Add(key, value);
    }

    private string GetConditionName(string match) {
      int end = match.IndexOf(">");
      return match.Substring(3, end - 3);
    }

    private string GetContentText(string match) {
      int start = match.IndexOf('>');
      int end = match.LastIndexOf('<');
      string text = match.Substring(start + 1, end - start - 1);
      return text.Trim('\r', '\n');
    }

    private ReplacementEntry CreateEntry(Match match) {
      string conditionName = GetConditionName(match.Value);
      bool conditionValue;
      if (!m_Conditions.TryGetValue(conditionName, out conditionValue)) {
        throw MapReportException.CreateException("Unknown condition: {0}", conditionName);
      }
      string contentText = GetContentText(match.Value);
      return new ReplacementEntry(match.Index, match.Index + match.Length, conditionValue ? contentText : String.Empty);
    }

    private string ReplaceConditions(string content) {
      Regex regex = new Regex(@"<(C:([A-Za-z][A-Za-z0-9]*))\b[^>]*>.*?</\1>", RegexOptions.Singleline);
      MatchCollection matches = regex.Matches(content);
      StringBuilder result = new StringBuilder();
      int currentIndex = 0;
      foreach (Match match in matches) {
        ReplacementEntry entry = CreateEntry(match);
        result.Append(content.Substring(currentIndex, entry.Start - currentIndex));
        result.Append(entry.Content);
        currentIndex = entry.End;
      }
      result.Append(content.Substring(currentIndex));
      return result.ToString();
    }

    private string ReplaceMessages(string content) {
      StringBuilder result = new StringBuilder();
      Regex regex = new Regex(@"<M:([A-Za-z][A-Za-z0-9]*)/>");
      MatchCollection matches = regex.Matches(content);
      int currentIndex = 0;
      foreach (Match match in matches) {
        string key = match.Value.Substring(3, match.Length - 5);
        string value;
        if (!m_Messages.TryGetValue(key, out value)) {
          throw MapReportException.CreateException("Unknown message: {0}", key);
        }
        result.Append(content.Substring(currentIndex, match.Index - currentIndex));
        result.Append(value);
        currentIndex = match.Index + match.Length;
      }
      result.Append(content.Substring(currentIndex));
      return result.ToString();
    }

    public string ApplyTo(string content) {
      if (content == null)
        throw new ArgumentNullException("content");

      return ReplaceMessages(ReplaceConditions(content));
    }
  }
}
